﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using Microsoft.Xaml.Behaviors;

namespace Tnelab.Wpf
{
    public class BlurForWindowBehavior:Behavior<Window>
    {
        Window _window;

        protected override void OnAttached()
        {
            base.OnAttached();
            //this._window = System.Windows.Window.GetWindow(this.AssociatedObject);
			this._window = this.AssociatedObject;
            this._window.SourceInitialized += _window_SourceInitialized;
        }

        private void _window_SourceInitialized(object sender, EventArgs e)
        {
			EnableBlurForWin10(_window, true);
			EnableBlurForWin7(_window, true);
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
			var windowHelper = new WindowInteropHelper(_window);
            if (windowHelper.Handle != IntPtr.Zero)
            {
				EnableBlurForWin10(_window, false);
				EnableBlurForWin7(_window, false);
            }
			this._window.SourceInitialized -= _window_SourceInitialized;
        }
		void EnableBlurForWin10(System.Windows.Window window, bool toBulr)
		{
			if (!IsWin10)
				return;
			var windowHelper = new WindowInteropHelper(window);

			var accent = new NativeMethods.AccentPolicy();
			if (toBulr)
				accent.AccentState = NativeMethods.AccentState.ACCENT_ENABLE_BLURBEHIND;
			else
				accent.AccentState = NativeMethods.AccentState.ACCENT_DISABLED;

			var accentStructSize = Marshal.SizeOf(accent);

			var accentPtr = Marshal.AllocHGlobal(accentStructSize);
			Marshal.StructureToPtr(accent, accentPtr, false);

			var data = new NativeMethods.WindowCompositionAttributeData();
			data.Attribute = NativeMethods.WindowCompositionAttribute.WCA_ACCENT_POLICY;
			data.SizeOfData = accentStructSize;
			data.Data = accentPtr;

			NativeMethods.SetWindowCompositionAttribute(windowHelper.Handle, ref data);

			Marshal.FreeHGlobal(accentPtr);
		}
		void EnableBlurForWin7(System.Windows.Window wndow, bool toBlur)
		{
			if (!IsWin7)
				return;
			if (!toBlur)
				return;
			if (!NativeMethods.DwmIsCompositionEnabled())
				return;

			var hwnd = new WindowInteropHelper(wndow).Handle;

			var hwndSource = HwndSource.FromHwnd(hwnd);

			wndow.Background = System.Windows.Media.Brushes.Transparent;
			hwndSource.CompositionTarget.BackgroundColor = Colors.Transparent;

			using (var path = new GraphicsPath())
			{
				System.Drawing.Rectangle rect = new(0, 0, (int)wndow.ActualWidth, (int)wndow.ActualHeight);
				path.AddRectangle(rect);

				using (var region = new Region(path))
				using (var graphics = Graphics.FromHwnd(hwnd))
				{
					var hRgn = region.GetHrgn(graphics);

					var blur = new NativeMethods.DWM_BLURBEHIND();
					blur.fEnable = toBlur;
					blur.fTransitionOnMaximized = toBlur;
					if (toBlur)
                    {
						blur.dwFlags = NativeMethods.DWM_BB.DWM_BB_ENABLE | NativeMethods.DWM_BB.DWM_BB_BLURREGION | NativeMethods.DWM_BB.DWM_BB_TRANSITIONONMAXIMIZED;
						blur.hRgnBlur = hRgn;
                    }

					NativeMethods.DwmEnableBlurBehindWindow(hwnd, ref blur);

					region.ReleaseHrgn(hRgn);
				}
			}
		}
		bool IsWin10 => Environment.OSVersion.Version.Major == 10;
		bool IsWin7 => Environment.OSVersion.Version.Major == 6
					   && Environment.OSVersion.Version.Minor == 1;
	}

	static partial class NativeMethods
	{
		public enum AccentState
		{
			ACCENT_DISABLED = 0,
			ACCENT_ENABLE_GRADIENT = 1,
			ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
			ACCENT_ENABLE_BLURBEHIND = 3,
			ACCENT_INVALID_STATE = 4,
			ACCENT_ENABLE_ACRYLICBLURBEHIND = 5
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct AccentPolicy
		{
			public AccentState AccentState;
			public int AccentFlags;
			public int GradientColor;
			public int AnimationId;
		}

		[StructLayout(LayoutKind.Sequential)]
		public struct WindowCompositionAttributeData
		{
			public WindowCompositionAttribute Attribute;
			public IntPtr Data;
			public int SizeOfData;
		}

		public enum WindowCompositionAttribute
		{
			// ...
			WCA_ACCENT_POLICY = 19
			// ...
		}
		[DllImport("user32.dll")]
		public static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data);

	}
	[SuppressUnmanagedCodeSecurity]
	static partial class NativeMethods
	{
		[StructLayout(LayoutKind.Sequential)]
		public struct DWM_BLURBEHIND
		{
			public DWM_BB dwFlags;
			public bool fEnable;
			public IntPtr hRgnBlur;
			public bool fTransitionOnMaximized;
		}

		[Flags]
		public enum DWM_BB
		{
			DWM_BB_ENABLE = 1,
			DWM_BB_BLURREGION = 2,
			DWM_BB_TRANSITIONONMAXIMIZED = 4
		}

		[DllImport("dwmapi.dll", PreserveSig = false)]
		public static extern bool DwmIsCompositionEnabled();

		[DllImport("dwmapi.dll", PreserveSig = false)]
		public static extern void DwmEnableBlurBehindWindow(IntPtr hwnd, ref DWM_BLURBEHIND blurBehind);
	}
}
